using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Abp.IdentityFramework;
using Abp.Localization;
using Abp.Runtime.Session;
using FwProject.Authorization;
using FwProject.Authorization.Roles;
using FwProject.Authorization.Users;
using FwProject.Roles.Dto;
using FwProject.Users.Dto;
using X.PagedList;
using Abp.Runtime.Caching;
using AutoMapper.QueryableExtensions;
using Abp.AutoMapper;
using Abp.ObjectMapping;
using System;
using JetBrains.Annotations;
using Abp;
using FwProject.JPush.JPushModel;
using FwProject.PublicService.JPush;
using FwProject.Comm;
using Abp.RemoteEventBus;

namespace FwProject.Users
{
    [AbpAuthorize]
    //[AbpAuthorize(PermissionNames.Pages_Users)]
    public class UserAppService : AsyncCrudAppService<User, UserDto, long, PagedResultRequestDto, CreateUserDto, UserDto>, IUserAppService
    {
        private readonly UserManager _userManager;
        private readonly RoleManager _roleManager;
        private readonly IRepository<User, long> _repositoryUser;
        public readonly IJPushAppservice _jPushAppservice;
        private readonly IRepository<Role> _roleRepository;
        private readonly IPasswordHasher<User> _passwordHasher;
        private readonly ICacheManager _cacheManager;
        public IObjectMapper _map { get; set; }
        public IRemoteEventBus remoteEventBus { get; set; }//缓存对象
        public UserAppService(
            IRepository<User, long> repository,
            UserManager userManager,
            RoleManager roleManager,
            IRepository<Role> roleRepository,
            IPasswordHasher<User> passwordHasher,
            ICacheManager cacheManager,
            IRepository<User, long> repositoryUser,
            IJPushAppservice jPushAppservice)
            : base(repository)
        {
            remoteEventBus = NullRemoteEventBus.Instance;
            _userManager = userManager;
            _roleManager = roleManager;
            _roleRepository = roleRepository;
            _passwordHasher = passwordHasher;
            _cacheManager = cacheManager;
            _repositoryUser = repositoryUser;
            _jPushAppservice = jPushAppservice;
        }

        public override async Task<UserDto> Create(CreateUserDto input)
        {
            CheckCreatePermission();

            var user = ObjectMapper.Map<User>(input);

            user.TenantId = AbpSession.TenantId;
            user.Password = _passwordHasher.HashPassword(user, input.Password);
            user.IsEmailConfirmed = true;

            CheckErrors(await _userManager.CreateAsync(user));

            if (input.RoleNames != null)
            {
                CheckErrors(await _userManager.SetRoles(user, input.RoleNames));
            }

            CurrentUnitOfWork.SaveChanges();

            return MapToEntityDto(user);
        }

        public override async Task<UserDto> Update(UserDto input)
        {
            CheckUpdatePermission();

            var user = await _userManager.GetUserByIdAsync(input.Id);

            MapToEntity(input, user);

            CheckErrors(await _userManager.UpdateAsync(user));

            if (input.RoleNames != null)
            {
                CheckErrors(await _userManager.SetRoles(user, input.RoleNames));
            }

            return await Get(input);
        }
        /// <summary>
        /// 返回当前对象体
        /// </summary>
        /// <returns>The dto.</returns>
        public async Task<UserDto> GetDto()
        {
            var user = await _userManager.GetUserByIdAsync(AbpSession.UserId.Value);
            return user.MapTo<UserDto>();
        }
        /// <summary>
        /// App当前对象是否具有该权限<see cref="PermissionNames" />参照查看
        /// </summary>
        /// <returns></returns>

        public async Task<bool> GetRoleByNamesPermission([NotNull] string PermissionNames)
        {
            Check.NotNull(PermissionNames, nameof(PermissionNames));
            return await _userManager.IsGrantedAsync(AbpSession.UserId.Value, PermissionNames);
        }
        /// <summary>
        /// App获取该用户的所有权限
        /// </summary>
        /// <returns></returns>
        public async Task<IReadOnlyList<Permission>> GetRoleByAllPermission()
        {
            var user = await _userManager.GetUserByIdAsync(AbpSession.UserId.Value);
            var roleId = user.Roles.Select(o => o.RoleId).FirstOrDefault();
            return await _roleManager.GetGrantedPermissionsAsync(roleId);
        }

        public override async Task Delete(EntityDto<long> input)
        {
            var user = await _userManager.GetUserByIdAsync(input.Id);
            await _userManager.DeleteAsync(user);
        }

        public async Task<ListResultDto<RoleDto>> GetRoles()
        {
            var roles = await _roleRepository.GetAllListAsync();
            return new ListResultDto<RoleDto>(ObjectMapper.Map<List<RoleDto>>(roles));
        }

        public async Task ChangeLanguage(ChangeUserLanguageDto input)
        {
            await SettingManager.ChangeSettingForUserAsync(
                AbpSession.ToUserIdentifier(),
                LocalizationSettingNames.DefaultLanguage,
                input.LanguageName
            );
        }
        /// <summary>
        /// 修改用户姓名
        /// </summary>
        /// <param name="id"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public async Task EditUserName(long id, string name)
        {
            var model = await _userManager.GetUserByIdAsync(id);
            model.Name = name;
            await _userManager.UpdateAsync(model);
        }
        public async Task EditFace(string face)
        {
            Logger.Debug($"{AbpSession.UserId.Value} 用户ID");
            var model = await _userManager.GetUserByIdAsync(AbpSession.UserId.Value);
            Logger.Debug(face);
            model.Face = face;

        }

        protected override User MapToEntity(CreateUserDto createInput)
        {
            var user = ObjectMapper.Map<User>(createInput);
            user.SetNormalizedNames();
            return user;
        }

        protected override void MapToEntity(UserDto input, User user)
        {
            ObjectMapper.Map(input, user);
            user.SetNormalizedNames();
        }

        protected override UserDto MapToEntityDto(User user)
        {
            var roles = _roleManager.Roles.Where(r => user.Roles.Any(ur => ur.RoleId == r.Id)).Select(r => r.NormalizedName);
            var userDto = base.MapToEntityDto(user);
            userDto.RoleNames = roles.ToArray();
            return userDto;
        }

        protected override IQueryable<User> CreateFilteredQuery(PagedResultRequestDto input)
        {
            return Repository.GetAllIncluding(x => x.Roles);
        }

        protected override async Task<User> GetEntityByIdAsync(long id)
        {
            return await Repository.GetAllIncluding(x => x.Roles).FirstOrDefaultAsync(x => x.Id == id);
        }

        protected override IQueryable<User> ApplySorting(IQueryable<User> query, PagedResultRequestDto input)
        {
            return query.OrderBy(r => r.UserName);
        }

        protected virtual void CheckErrors(IdentityResult identityResult)
        {
            identityResult.CheckErrors(LocalizationManager);
        }
        public async Task<IPagedList<UserDto>> GetPagedListAsync(int pageIdx, int pageSize, string factoryid, string type, string keyword)
        {
            IQueryable<User> query = (await GetCache).AsQueryable();//_contactRepository.GetAll();
            if (!string.IsNullOrWhiteSpace(factoryid))
            {
                Guid faid = new Guid(factoryid);
                if (faid != Guid.Empty)
                {
                    query = query.Where(o => o.FactoryinfoId == faid);

                    if (!string.IsNullOrWhiteSpace(type))
                    {
                        if (type != "GC")//判断是否是否查看工厂下所有人员
                        {
                            switch (type)
                            {
                                case "工厂老板":
                                    query = query.Where(o => o.EmployeeType == EmployeeType.工厂老板);
                                    break;
                                case "员工类型":
                                    query = query.Where(o => o.EmployeeType == EmployeeType.员工类型);
                                    break;
                                case "司机类型":
                                    query = query.Where(o => o.EmployeeType == EmployeeType.司机类型);
                                    break;
                                case "餐厅老板类型":
                                    query = query.Where(o => o.EmployeeType == EmployeeType.餐厅老板类型);
                                    break;
                                default:
                                    break;
                            }
                        }
                    }
                }
            }

            if (!string.IsNullOrWhiteSpace(keyword))
                query = query.Where(o => o.Name.Contains(keyword) || o.Mobile.Contains(keyword) || o.UserName.Contains(keyword));

            var data = await query.OrderByDescending(o => o.Id).ProjectTo<UserDto>().ToPagedListAsync(pageIdx, pageSize);
            return data;
        }
        public async Task<List<UserExportDto>> GetUserListAsync()
        {
            var usermodel = await _repositoryUser.GetAsync(AbpSession.UserId.Value);
            var model = _repositoryUser.GetAll();

            return await model.Where(o => o.FactoryinfoId == usermodel.FactoryinfoId).ProjectTo<UserExportDto>().ToListAsync();
        }
        public async Task<UserDto> GetByIdUserAsync(long id)
        {
            return ObjectMapper.Map<UserDto>((await GetEntityByIdAsync(id)));
        }


        public async Task<List<UserDto>> GetAllPersonAsync()
        {
            var model = (await GetCache).Where(o => o.EmployeeType == EmployeeType.司机类型 || o.EmployeeType == EmployeeType.员工类型 || o.EmployeeType == EmployeeType.工厂老板).AsQueryable();
            return model.ProjectTo<UserDto>().ToList();
        }

        public async Task<UserDto> GetUserByMobile(string Mobile)
        {
            var model = (await GetCache).AsQueryable().Where(o => o.Mobile == Mobile).FirstOrDefault();

            return _map.Map<UserDto>(model);
        }

        public async Task CreateAndGitIdAsync(CreateUserDto input)
        {
            await Create(input);
        }

        public async Task EditAsync(long id, UserEnterDto input)
        {
            var entity = await _repositoryUser.FirstOrDefaultAsync(id);
            entity = input.MapTo(entity);
            entity.UserName = input.Mobile;
            //await _userManager.UpdateAsync(entity);
            CheckErrors(await _userManager.UpdateAsync(entity));

            if (input.RoleNames != null)
                CheckErrors(await _userManager.SetRoles(entity, input.RoleNames));
        }

        public async Task<UserEnterDto> GetEnterEntityAsync(long id)
        {
            var entity = await _repositoryUser.GetAll().Where(o => o.Id == id).Include(o => o.FactoryinfoModel).FirstAsync();
            var dto = entity.MapTo<UserEnterDto>();
            dto.FactoryinfoName = entity.FactoryinfoModel.FactoryName;

            return dto;
        }

        public async Task DeleteAsync(long id)
        {
            var entity = (await GetCache).AsQueryable().Where(o => o.Id == id).First();
            await _userManager.DeleteAsync(entity);
        }

        public async Task<List<UserOutputDto>> GetAllByTypeAsync(EmployeeType type, Guid? factoryinfoId, string keyword)
        {
            var query = (await GetCache).AsQueryable().Where(o => o.EmployeeType == type);

            if (!IsGranted(PermissionNames.User_All_View))
            {
                var user = await _userManager.FindByIdAsync(AbpSession.UserId.Value.ToString());
                query = query.Where(o => o.FactoryinfoId == user.FactoryinfoId);
            }
            else if (factoryinfoId.HasValue)
            {
                query = query.Where(o => o.FactoryinfoId == factoryinfoId.Value);
            }

            if (!string.IsNullOrWhiteSpace(keyword))
                query = query.Where(o => o.Name.Contains(keyword));

            return query.OrderBy(o => o.Id).ProjectTo<UserOutputDto>().ToList();
        }

        public async Task<List<UserOutputDto>> GetAllListAsync(string keyword)
        {
            var query = (await GetCache).AsQueryable();

            if (!IsGranted(PermissionNames.User_All_View))
            {
                var user = await _userManager.FindByIdAsync(AbpSession.UserId.Value.ToString());
                query = query.Where(o => o.FactoryinfoId == user.FactoryinfoId);
            }
            if (!string.IsNullOrWhiteSpace(keyword))
                query = query.Where(o => o.Name.Contains(keyword));

            return query.OrderBy(o => o.Id).ProjectTo<UserOutputDto>().ToList();
        }


        public async Task<List<UserOutputDto>> GetAllAgentPeoperAsync()
        {
            var query = (await GetCache).AsQueryable().Where(o => o.EmployeeType == EmployeeType.员工类型 || o.EmployeeType == EmployeeType.司机类型);

            if (!IsGranted(PermissionNames.User_All_View))
            {
                var user = await _userManager.FindByIdAsync(AbpSession.UserId.Value.ToString());
                query = query.Where(o => o.FactoryinfoId == user.FactoryinfoId);
            }

            return query.OrderBy(o => o.Id).ProjectTo<UserOutputDto>().ToList();
        }

        public void UserPushMessage(List<long> ids, string Message)
        {
            SystemPushMessageDto dto = new SystemPushMessageDto()
            {
                UserId = ids,
                Message = Message
            };
            var eventDate = new RemoteEventData(RemoteTypeHelp.TypeUserPushMessage)
            {
                Data = { [RemoteTypeHelp.ListT] = dto }
            };
            remoteEventBus.Publish(RemoteTypeHelp.TopicUser, eventDate);
        }

        private Task<List<User>> GetCache
        {
            get
            {
                ICache cache = _cacheManager.GetCache(nameof(User));
                return cache.GetAsync("list", async () => await Repository.GetAllListAsync());
            }

        }
    }
}
